using System;
using System.Web.Services;
using Microsoft.SharePoint.Administration;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using Microsoft.SharePoint;

namespace Codeplex.STSDTS.Services
{
    [WebService(Namespace = "http://stsdts.codeplex.com/")]
    public class DeploymentService
    {

        private readonly SPFarm _localFarm = SPFarm.Local;

        /// <summary>
        /// Installs a solution or upgrade if it already is installed
        /// </summary>
        /// <param name="solutionFile">WSP file</param>
        /// <param name="solutionId">Guid of the solution</param>
        /// <param name="solutionFileName">Filename of the solution</param>
        [WebMethod]
        public bool InstallSolution(byte[] solutionFile, Guid solutionId, string solutionFileName)
        {
            try
            {
                var tempFileName = string.Format("{0}{1}", Path.GetTempPath(), solutionFileName);
                var tempFile = new FileInfo(tempFileName);
                if (tempFile.Exists)
                    tempFile.Delete();
                using (var fs = new FileStream(tempFileName, FileMode.CreateNew))
                {
                    fs.Write(solutionFile, 0, solutionFile.Length);
                }
                //Check if solution is already installed
                var solution = _localFarm.Solutions[solutionId];

                if (solution == null)
                {
                    //Add solution to store as it does not exist
                    _localFarm.Solutions.Add(tempFileName);
                }
                else
                {
                    //Exists in solutionstore
                    if (solution.Deployed)
                    {
                        solution.Upgrade(tempFileName);
                    }
                    else
                    {
                        solution.Delete();
                        _localFarm.Solutions.Add(tempFileName);
                    }
                }
                //Delete tempfile
                tempFile.Delete();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Deploys solution to given webapplications
        /// </summary>
        /// <param name="solutionId">Guid of the solutions</param>
        /// <param name="webApplicationUrls">Urls of the webapplication</param>
        [WebMethod]
        public void DeploySolution(Guid solutionId, List<string> webApplicationUrls)
        {
            var solution = _localFarm.Solutions[solutionId];
            if (webApplicationUrls == null || webApplicationUrls.Count == 0)
            {
                //check if solution not is deployed
                if (!solution.Deployed)
                {
                    solution.Deploy(DateTime.Now, true, true);
                    //Wait on deployment job
                    Utils.WaitOnSolutionJob(solution);
                }
            }
            else
            {
                //Retrieve webapplications to deploy solution for
                var webApplications = new Collection<SPWebApplication>();
                foreach (var url in webApplicationUrls)
                {
                    var webApplication = SPWebApplication.Lookup(new Uri(url));
                    if (webApplication != null)
                        webApplications.Add(webApplication);
                }
                //check if solution not is deployed
                if (!solution.Deployed)
                {
                    solution.Deploy(DateTime.Now, true, webApplications, true);
                    //Wait on deployment job
                    Utils.WaitOnSolutionJob(solution);
                }
            }
        }

        /// <summary>
        /// Retracts solution with given ID
        /// </summary>
        /// <param name="solutionId">ID of the solution</param>
        [WebMethod]
        public void RetractSolution(Guid solutionId)
        {
            _localFarm.Solutions[solutionId].RetractLocal();
            while (_localFarm.Solutions[solutionId].Deployed)
            {
                Utils.WaitOnSolutionJob(_localFarm.Solutions[solutionId]);
            }
        }

        /// <summary>
        /// Deletes solution with given ID
        /// </summary>
        /// <param name="solutionId">ID of the solution</param>
        [WebMethod]
        public void DeleteSolution(Guid solutionId)
        {
            _localFarm.Solutions[solutionId].Delete();
        }

        /// <summary>
        /// Activates feature on web
        /// </summary>
        /// <param name="featureId">ID of the feature</param>
        /// <param name="url">URL of the web</param>
        [WebMethod]
        public void ActivateFeatureOnWeb(Guid featureId, string url)
        {
            using (var site = new SPSite(url))
            {
                using (var web = site.OpenWeb(url.Replace(site.Url, string.Empty)))
                {
                    web.Features.Add(featureId);
                }
            }
        }

        /// <summary>
        /// Activates feature on sitecollection
        /// </summary>
        /// <param name="featureId">ID of the feature</param>
        /// <param name="url">URL of the sitecollection</param>
        [WebMethod]
        public void ActivateFeatureOnSite(Guid featureId, string url)
        {
            using (var site = new SPSite(url))
            {
                site.Features.Add(featureId);
            }
        }

        /// <summary>
        /// Activates feature on webapplication
        /// </summary>
        /// <param name="featureId">ID of the feature</param>
        /// <param name="url">URL of the webapplication</param>
        [WebMethod]
        public void ActivateFeatureOnWebApplication(Guid featureId, string url)
        {
            var webApplication = SPWebApplication.Lookup(new Uri(url));
            webApplication.Features.Add(featureId);
        }

        /// <summary>
        /// Downloads given solution
        /// </summary>
        /// <param name="solutionId">ID of the solution to download</param>
        /// <returns>Buffer containing solutionfile</returns>
        [WebMethod]
        public byte[] DownloadSolution(Guid solutionId)
        {
            var solution = _localFarm.Solutions[solutionId];
            var tempFilePath = Path.GetTempFileName();
            solution.SolutionFile.SaveAs(tempFilePath);
            //Create tempfile
            var solutionFile =
                new FileInfo(tempFilePath);
            byte[] result;
            using (var stream = solutionFile.OpenRead())
            {
                result = new byte[stream.Length];
                stream.Read(result, 0, (int)stream.Length);
            }
            //Delete temp file
            solutionFile.Delete();
            return result;
        }

    }
}